home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr51 / fastpack.zip / FASTPACK.ASM < prev    next >
Assembly Source File  |  1993-04-05  |  33KB  |  847 lines

  1. ;       Program: Fastpack.asm - source code for a fast .dbf file pack routine.
  2. ;       Author: R. Russell Freeland / modified by Jay Parsons.
  3. ;       Notice: This code is a modification of the Fastpack.asm code found in
  4. ;               dBASE POWER: Building and Using Programming Tools, by P. L.
  5. ;               Olympia, R. Russell Freeland and Randy Wallin, published and
  6. ;               copyright by Ashton-Tate Corporation, 1988.
  7.  
  8. ;       Mods:   Modified by Jay Parsons, December, 1989 as follows:
  9. ;               1) Only one write to screen per buffer.
  10. ;               2) Pack-then-write algorithm implemented.
  11. ;                       (Above improve speed for small records.)
  12. ;               3) Header of packed file updated to current date.
  13. ;               4) Packed file given original extension.
  14. ;               5) Assembly option for runnable .exe and .com files added.
  15. ;               6) Assembly option for 80386 and related instructions added.
  16. ;               7) Command/assembly option for no screen writing added.
  17. ;               8) Command/assembly option for no backup file added.
  18. ;               9) Numerous insignificant changes due to programmer style.
  19.  
  20. ;----------------------------------------------------------------------------
  21.  
  22. ;                       Assembly Options
  23.  
  24. false           equ 0                           ; definitions required
  25. true            equ -1                          ; for options
  26.  
  27. ;       Change the false in the following line to true before assembly if you
  28. ;       will be debugging the program within dBASE by starting dBASE with the
  29. ;       DOS command "DEBUG dBASE."
  30.  
  31. debugging       equ false
  32.  
  33. ;       Change the false in the following line to true before assembly
  34. ;       to link into a runnable .exe file convertible into a .com file.
  35. ;       Must remain false to create a file convertible to a dBASE .bin file.
  36.  
  37. DOSexe          equ false
  38.                                                       
  39. ;       Change the false in the following line to true before assembly to
  40. ;       assemble using instructions available only on an 80386 processor.
  41. ;       The resulting program will not run on any earlier processor.
  42.  
  43. for386          equ false
  44.  
  45. if for386
  46. .386
  47. endif
  48.  
  49. ;       Make one of the three following choices true before assembly:
  50. ;       noterse - program will display number of records copied on the screen.
  51. ;       allterse - program will display nothing on the screen.
  52. ;       terseopt - program accepts /T switch for terse, otherwise is noterse.
  53. ;       allterse is faster than noterse; terseopt code is longer.
  54.                                                                              
  55. allterse        equ false
  56. noterse         equ false
  57. terseopt        equ true
  58.  
  59. ;       Make one of the three following choices true before assembly:
  60. ;       nobak - program will pack the original file.
  61. ;       allbak - program will create a packed file and leave original as .bak.
  62. ;       bakopt - program accepts /N switch for nobak, otherwise is allbak.
  63. ;       nobak is considerably faster than allbak and does not require disk
  64. ;       space for the new file, but risks data loss;  bakopt code is longer.
  65.  
  66. allbak          equ false
  67. nobak           equ false
  68. bakopt          equ true
  69.  
  70. ;       File buffer size (applies only if DOSexe is false, to .bin files).
  71. ;       A larger buffer will allow the program to run more quickly, but will
  72. ;       use scarce dBASE memory.  The buffer size should always be at least
  73. ;       the size of the maximum possible .dbf file header, 8K+1 (8,193) bytes,
  74. ;       unless it can be assured that all actual file headers will be shorter
  75. ;       than the buffer size chosen.
  76.  
  77. buffsize        equ 12288
  78.  
  79. ;----------------------------------------------------------------------------
  80.  
  81. ;       IF YOU CHANGE THE CODE BELOW THIS LINE, YOU ARE ON YOUR OWN
  82.  
  83. ;----------------------------------------------------------------------------
  84.  
  85. ;               Selectors and Macros
  86.  
  87. if              allterse
  88. tcond           equ 1
  89. else
  90. if              noterse
  91. tcond           equ 0
  92. else
  93. tcond           equ -1
  94. endif
  95. endif
  96.  
  97. if              allbak
  98. bcond           equ 1
  99. else
  100. if              nobak
  101. bcond           equ 0
  102. else
  103. bcond           equ -1
  104. endif
  105. endif
  106.  
  107. if              tcond LT 0
  108. eitheropt       equ true
  109. else
  110. if              bcond LT 0
  111. eitheropt       equ true
  112. else
  113. eitheropt       equ false
  114. endif
  115. endif
  116.  
  117. BTEST           MACRO jump                      ; test bakup=true, cond. jump
  118. if              bcond LT 0
  119.                 cmp bakup,true
  120.                 jump
  121. endif
  122. ENDM
  123.  
  124. CLOSE           MACRO handle                    ; close file "handle"
  125.                 LOCAL notopen
  126.                 mov bx,handle
  127.                 cmp bx,0                        ; don't close stdin
  128.                 jz notopen
  129.                 mov ax,3e00h
  130.                 int 21h
  131. notopen:
  132. ENDM
  133.  
  134. ;----------------------------------------------------------------------------
  135.  
  136. ;                       Program Definitions
  137.  
  138. ;       Return codes to dBASE showing result of program
  139.  
  140. ok_flag         equ 1                           ; no problems
  141. header_err      equ 2                           ; header error (no such file?)
  142. write_err       equ 3                           ; error in writing new file
  143. read_err        equ 5                           ; error in reading old one
  144.  
  145. ;       Other definitions
  146.  
  147. eof_mark        equ 26
  148. del_mark        equ '*'
  149. dot             equ '.'
  150. slash           equ '/'
  151. space           equ ' '
  152. fnamelen        equ 127                         ; length of a path and filename
  153. maxheader       equ 255*32+33                   ; 255 field descriptors of 32
  154.                                                 ; bytes, 32 for the main header
  155.                                                 ; and 0dh.  Equals 8K+1.
  156.  
  157. ;       First 12 bytes of the .dbf header (first 12 bytes of the 32-byte
  158. ;       main header preceding the field descriptor array) give the lengths we
  159. ;       need of the header and records, plus the date and count we must change.
  160.  
  161. dbf_header      STRUC
  162.  
  163. memo_ind        db ?                            ; .dbf version and .dbt flag
  164. year            db ?                            ; date of last update
  165. month           db ?                            ;       ditto
  166. day             db ?                            ;       ditto
  167.  
  168. if for386
  169. rec_count       dd ?
  170. else
  171. rec_count       dw 2 dup(?)                     ; reccount() as doubleword
  172. endif
  173.  
  174. header_len      dw ?                            ; length of total header
  175. rec_len         dw ?                            ; length of a data record
  176.  
  177. dbf_header      ENDS
  178.  
  179. year_offset     equ 1                           ; bytes from start to year
  180. date_n_count    equ 7                           ; bytes in date and count
  181.  
  182. ;----------------------------------------------------------------------------
  183.  
  184. ;                       Code and Data
  185.  
  186. if              for386
  187. CODESEG         Segment USE16 'CODE'
  188. else
  189. CODESEG         Segment 'CODE'
  190. endif
  191.                 assume CS:CODESEG
  192.  
  193. if              DOSexe
  194.                 org 100h
  195.  
  196. ;       This routine is not part of the fastpack program but a wraparound to
  197. ;       create an .exe file which may be run from DOS.  See Assembly Options.
  198.  
  199. start:          mov bx,80h                      ; argument portion of PSP
  200.                 mov al,byte ptr [bx]            ; command count
  201.                 cmp al,0                        ; if any
  202.                 jz noarg
  203.                 cbw                             ; as a word
  204.                 inc bx                          ; skip space
  205.                 mov di,ax
  206.                 add di,bx                       ; point di to the 0dh
  207.                 xor al,al
  208.                 stosb                           ; replace 0dh with ASCIIZ
  209.                 call fastpack
  210. noarg:          mov ah,4ch                      ; return to DOS with code in al
  211.                 int 21h
  212.  
  213. ;---------------------------------------------------------------------------
  214.  
  215. ;       Fastpack - main routine of the program.
  216. ;       Sets up filenames, opens files, calls subroutines, closes files.
  217.  
  218. fastpack        proc near                       ; if DOSexe, near for .COM
  219. else
  220. fastpack        proc far                        ; else far for a dBASE .BIN
  221. start:                                          ; and start with it
  222. endif                                           ; DOSexe
  223.  
  224.                 jmp begin                       ; usual jump over data
  225.  
  226. ;       data storage area
  227.  
  228. ife             DOSexe
  229. old_fname       db fnamelen dup(0)              ; path & name of source file
  230. new_fname       db fnamelen dup(0)              ; & target file
  231. endif
  232.                 even
  233.  
  234. old_handle      dw ?                            ; their DOS handles
  235. new_handle      dw ?
  236.  
  237. if              bcond LT 1
  238. read_ptr        dw 2 dup(?)
  239. write_ptr    dw 2 dup(?)
  240. endif
  241.  
  242. dbf             dbf_header <>                   ; storage of the header info
  243.  
  244. read_len        dw ?                            ; # bytes in use; done if 0
  245.  
  246. ife             DOSexe
  247. rw_buff         db buffsize dup(?)              ; must be > maximum header size
  248. endif
  249.  
  250. db_extension    db '.DBF',0
  251. new_extension   db '$$$',0
  252. old_extension   db 'BAK',0
  253.  
  254. if              tcond LT 0
  255. terse           db ?                            ; true if no screen writes
  256. endif
  257. if              bcond LT 0
  258. bakup           db ?                            ; true if backup file
  259. endif
  260.  
  261. count           db 8 dup(?)                     ; storage for # of records
  262. count_msg       db ' records copied',13,'$'     ; and balance of message
  263.  
  264. begin:
  265. if              debugging
  266.                 int 3                           ; pass control to DEBUG
  267. endif
  268.  
  269. ;       actual start of program code
  270.  
  271.                 push ds                         ; save argument pointer
  272.                 push bx
  273.                 mov bp,sp                       ; and stack frame
  274.  
  275.                 cld
  276.                 les di,[bp]                     ; point es:di to argument
  277.                 mov cx,-1                       ; can't go this far
  278.                 mov al,space                    ; strip leading spaces
  279.                 repe scasb
  280.                 dec di                          ; point to first non-space
  281.                 mov bx,di                       ; and save pointer
  282.                 xor al,al                       ; look for the ASCIIZ
  283.                 mov cx,-1
  284.                 repne scasb
  285.                 not cx                          ; and convert the count
  286.  
  287.                 mov ax,cs                       ; destination is our segment
  288.                 mov es,ax
  289.  
  290.                 mov di,offset old_fname         ; copy the argument
  291.                 mov si,bx                       ; skipping spaces
  292.                 rep movsb                       ; including the ASCIIZ
  293.                 mov ds,ax                       ; no more need for argument
  294.  
  295.                 assume ds:codeseg,es:codeseg    ; nor for other segments
  296.  
  297.                 call parse            ; parse argument
  298.         mov old_handle,0        ; flag for no file open
  299.         mov new_handle,0
  300.                 call read_header                ; read the file header
  301.                 mov al,header_err
  302.                 jc shorthop
  303.  
  304. if              bcond LT 1                      ; (0) /these numbers are
  305. if              for386                          ; (1) /nesting levels of ifs
  306.                 mov eax,dword ptr read_ptr
  307.                 mov dword ptr write_ptr,eax
  308. else
  309.                 mov ax,read_ptr
  310.                 mov write_ptr,ax
  311.                 mov ax,read_ptr+2
  312.                 mov write_ptr+2,ax
  313. endif                                           ; for386 (1)
  314. endif                                           ; bcond LT 1 (0)
  315.  
  316. if              DOSexe
  317.                 mov ax,offset rw_buff           ; .exe buffer size is entire
  318.                 not ax                          ; segment less code
  319.                 sub ax,80h                      ; and room for stack
  320. else
  321.                 mov ax,size rw_buff             ; .bin buffer must be internal
  322. endif
  323.                 xor dx,dx
  324.                 mov cx,dbf.rec_len
  325.                 div cx                          ; discard partial record
  326.                 mul cx                          ; keep the whole records
  327.                 cmp ax,0                        ; if a whole one will fit
  328.                 jnz buff_ok
  329.                 mov al,header_err
  330. shorthop:       jmp short finish
  331.  
  332. buff_ok:        mov read_len,ax                 ; and save length in use
  333.  
  334.                 BTEST <jnz nonew>
  335. if              bcond
  336.                 mov ah,3ch                      ; create the new file
  337.                 mov dx,offset new_fname
  338.                 xor cx,cx
  339.                 int 21h
  340.                 jnc makenew                     ; go on if no error
  341.                 mov cl,write_err
  342.                 jmp short finish
  343. endif                                           ; bcond
  344. if              bcond LT 1
  345. nonew:          mov ax,old_handle
  346.                 mov new_handle,ax
  347.                 jmp short rw
  348. endif                                           ; bcond LT 1
  349. if              bcond
  350. makenew:        mov bx,ax
  351.                 mov new_handle,bx               ; save new handle
  352.                 mov cx,dbf.header_len           ; length of the header
  353.                 mov dx,offset rw_buff
  354.                 mov ax,4000h                    ; write header to new file
  355.                 int 21h
  356.                 mov al,write_err                ; quit on error
  357.                 jc finish
  358. endif                                           ; bcond
  359.  
  360. rw:             call readwrite                  ; now do the data
  361.                 jc finish
  362.  
  363.                 BTEST <jz doheader>
  364. if              bcond LT 1
  365.                 mov bx,old_handle
  366.         xor cx,cx            ; dx doesn't matter    
  367.                 mov ah,40h                      ; truncate file at pointer
  368.         int 21h
  369. endif
  370.  
  371. doheader:       call fix_header                 ; fix up the header
  372.                 jc finish
  373.                 mov al,ok_flag                  ; sign of success
  374.  
  375. finish:         mov dx,ax                       ; save success/error code
  376.                 CLOSE old_handle                ; close the open files
  377.                 BTEST <jnz finish2>
  378. if              bcond
  379.                 CLOSE new_handle
  380. endif
  381.  
  382. finish2:        mov ax,dx                       ; no file-closing errors
  383.                 cmp al,1
  384.                 jnz alldone
  385.                 BTEST <jnz alldone>
  386. if              bcond
  387.                 call rename                     ; change names if two files
  388. endif
  389.  
  390. alldone:        mov sp,bp                       ; reset stack for safety
  391.                 pop bx
  392.                 pop ds                          ; restore argument pointers
  393.                 mov [bx],al                     ; write return code and done
  394.                 ret
  395. fastpack        endp
  396.  
  397. ;---------------------------------------------------------------------------
  398.  
  399. ;       parse - parse argument for filename and switches.
  400. ;       Capitalizes filename at old_fname.  Sets terse and bakup.
  401. ;       If bakup is false, puts name of new file into new_fname.
  402.  
  403. parse           proc near
  404.                 mov si,offset old_fname
  405.                 xor dx,dx                       ; a pair of zeroes
  406. if              tcond LT 0
  407.                 mov terse,false                 ; reset terse and bakup
  408. endif
  409. if              bcond LT 0
  410.                 mov bakup,true
  411. endif
  412.  
  413. caploop:        lodsb
  414.                 cmp al,0                        ; at end yet?
  415.                 jz gotchars
  416.  
  417. if eitheropt                                    ; (0)
  418.                 cmp al,slash                    ; signal for a switch?
  419.                 jnz getchar2
  420.                 cmp dh,true
  421.                 jz testopt
  422.                 mov dh,true
  423.                 mov di,si
  424. testopt:        mov al,[si]
  425.                 and al,5fh                      ; capitalize
  426. if              tcond LT 0                      ; (1)
  427.                 cmp al,'T'                      ; terse?
  428.                 jnz getbak
  429.                 mov terse,true                  ; make it so
  430.                 jmp short caploop
  431. getbak:
  432. endif                                           ; tcond LT 0 (1)
  433. if              bcond LT 0                      ; (1)
  434.                 cmp al,'N'                      ; no backup?
  435.                 jnz caploop                     ; if not, ignore it
  436.                 mov bakup,false
  437.                 jmp short caploop
  438. endif                                           ; bcond LT 0 (1)
  439. endif                                           ; eitheropt (0)
  440.  
  441. getchar2:       cmp al,dot
  442.                 jnz getchar3
  443.                 cmp dl,true                     ; already got one?
  444.                 jz caploop                      ; then ignore it
  445.                 cmp dh,true
  446.                 jz caploop                      ; or if past filename
  447.                 mov dl,true                     ; flag for dot
  448.                 mov bx,si                       ; point past the dot
  449.                 jmp short caploop
  450.  
  451. getchar3:       cmp al,space
  452.                 jnz capit
  453. if eitheropt                                    ; (0)
  454.                 cmp dh,true                     ; got name end already?
  455.                 jz caploop                      ; then ignore it
  456.                 mov dh,true
  457.                 mov di,si                       ; point past filename
  458.                 jmp short caploop
  459. else
  460.                 jmp short gotchars
  461. endif                                           ; eitheropt (0)
  462.  
  463. capit:          cmp al,'a'
  464.                 jb caploop
  465.                 and byte ptr [si-1],5fh         ; capitalize it
  466.                 jmp short caploop
  467.  
  468. gotchars:
  469. if eitheropt
  470.                 cmp dh,true                     ; found any spaces or slash?
  471.                 jz checkz
  472. endif
  473.                 mov di,si                       ; if not, this is past name end
  474. checkz:         mov byte ptr [di-1],0           ; add ASCIIZ in case needed
  475.                 cmp dl,true                     ; already got a dot?
  476.                 jz gotdot                       ; then move on
  477.                 mov bx,di                       ; pointer will be past dot
  478.                 dec di
  479.                 mov si,offset db_extension      ; add .dbf,0
  480.                 mov cx,5
  481.                 rep movsb
  482.  
  483. gotdot:
  484.                 BTEST <jnz parsedone>
  485. if bcond
  486.                 mov cx,bx                       ; pointer past the dot
  487.                 mov si,offset old_fname
  488.                 sub cx,si                       ; cx now length thru dot
  489.                 mov di,offset new_fname
  490.                 rep movsb                       ; copy old name to new
  491.                 mov si,offset new_extension
  492.                 mov cx,4
  493.                 rep movsb                       ; and add new extension
  494. endif
  495. parsedone:      ret
  496. parse           endp
  497.  
  498. ;---------------------------------------------------------------------------
  499.  
  500. ;       read_header - read the header of the old file, save key data
  501. ;       returns with carry set in case of i/o error
  502.  
  503. read_header     proc near
  504.                 mov dx,offset old_fname         ; open the old file
  505.  
  506.                 BTEST <jz read_open>
  507. if              bcond LT 1
  508.                 mov ax,3d02h                    ; for read or write
  509. endif
  510. if              bcond
  511.                 jmp short any_open
  512. read_open:      mov ax,3d00h                    ; for read only
  513. endif
  514.  
  515. any_open:       int 21h
  516.                 jc readfin
  517.                 mov bx,ax
  518.                 mov old_handle,bx               ; save handle
  519.                 mov dx,offset rw_buff
  520.                 mov cx,maxheader                ; read maximum header length
  521.                 mov ax,3f00h
  522.                 int 21h
  523.                 jc readfin
  524.                 mov di,offset dbf               ; copy first 12 bytes to dbf
  525.                 mov cx,size dbf_header
  526.                 mov si,dx
  527.                 rep movsb
  528.                 mov dx,dbf.header_len           ; cx=0 and bx=handle already
  529. if              bcond LT 1
  530.                 mov read_ptr,dx                 ; save pointer
  531.                 mov read_ptr+2,cx
  532. endif
  533.                 mov ax,4200h                    ; point past header for read
  534.                 int 21h
  535. readfin:        ret
  536. read_header     endp
  537.  
  538. ;---------------------------------------------------------------------------
  539.  
  540. ;       readwrite - main processing.  Read a full buffer of data,
  541. ;       pack it to remove deleted records, write it, print progress and
  542. ;       continue until done.
  543.  
  544. ;       Speed in "readnext" loop is important to performance of the program.
  545.  
  546. readwrite       proc near
  547.  
  548.                 mov di,offset count             ; clear count buffer
  549. if for386
  550.                 mov dword ptr dbf.rec_count,0
  551.                 mov eax,'    '                  ; four spaces
  552.                 stosd                           ; twice
  553.                 stosd
  554. else
  555.                 mov word ptr dbf.rec_count,0    ; initialize record count
  556.                 mov word ptr dbf.rec_count+2,0
  557.                 mov ax,'  '                     ; two spaces
  558.                 mov cx,4                        ; times 4
  559.                 rep stosw
  560. endif
  561.  
  562. readnext:       mov bx,old_handle               ; from old file
  563.                 mov cx,read_len
  564.                 mov dx,offset rw_buff           ; read them into the buffer
  565.                 mov ax,3f00h
  566.                 int 21h
  567.                 jnc readok
  568. readerr:        mov al,read_err
  569.                 ret
  570.  
  571. readok:         mov bx,dx                       ; start of data
  572.                 add dx,ax                       ; end of data
  573.                 cmp ax,cx                       ; got full buffer?
  574.                 jz gotfull                      ; okay
  575.                 mov read_len,0                  ; else flag for all done
  576.                 mov si,dx
  577.                 cmp byte ptr [si-1],eof_mark    ; got an eof?
  578.                 jnz nowpack                     ; if not, carry on
  579.                 dec dx                          ; else drop the eof_mark
  580.  
  581. if              bcond LT 1
  582.                 jmp short nowpack
  583. endif
  584.  
  585. gotfull:
  586.                 BTEST <jz nowpack>
  587. if              bcond LT 1                      ; (0)
  588. if              for386                          ; (1)
  589.         movzx eax,cx            ; else reset for next read
  590.         add dword ptr read_ptr,eax
  591. else
  592.                 add word ptr read_ptr,ax
  593.                 adc word ptr read_ptr+2,0
  594. endif                                           ; for386 (1)
  595. endif                                           ; bcond LT 1 (0)
  596.                 
  597. nowpack:        call packdata                   ; pack the buffer
  598.                 call writebuff                  ; and write it
  599.                 jc writerr
  600.                 xor dx,dx                       ; ax holds bytes written
  601.                 div dbf.rec_len                 ; divide for records written
  602.  
  603. if              for386
  604.                 cwde                            ; records cannot exceed 32,000
  605.                 add eax,dbf.rec_count           ; add previous totals
  606.                 mov dbf.rec_count,eax           ; and save the new
  607. else
  608.                 xor dx,dx                       ; ignore remainder (eof_mark)
  609.                 add ax,dbf.rec_count            ; add previous totals
  610.                 adc dx,dbf.rec_count+2
  611.                 mov dbf.rec_count,ax            ; save new totals
  612.                 mov dbf.rec_count+2,dx
  613. endif
  614. if              tcond LT 0
  615.                 cmp byte ptr terse,true
  616.                 jz readon
  617. endif
  618. if              tcond LT 1
  619.                 mov bx,offset count_msg         ; point to the message
  620.                 call convertit                  ; convert total to ASCII
  621.                 mov dx,offset count
  622.                 mov ah,9                        ; print it
  623.                 int 21h
  624. endif
  625. readon:         cmp read_len,0
  626.                 jz rwdone
  627.                 BTEST <jz readnext>
  628. if              bcond LT 1
  629.                 mov bx,old_handle
  630.                 mov dx,read_ptr                 ; offset
  631.         mov cx,read_ptr+2
  632.         mov ax,4200h            ; from start of file    
  633.         int 21h                ; go there
  634. endif
  635.                 jmp readnext
  636.  
  637. writerr:        mov al,write_err
  638. rwdone:         ret
  639. readwrite       endp
  640.  
  641. ;---------------------------------------------------------------------------
  642.  
  643. ;       packdata - pack the undeleted data records, held in the buffer from
  644. ;       (ds: and es:) bx to dx, into the lowest part of it.
  645. ;       Destroys ax,cx,si; returns with di pointing to end of packed data.
  646. ;       Uses value held in dbf.rec_len and definition of del_mark.
  647.  
  648. packdata        proc near                       ; must be near--see below
  649.                 mov cx,dbf.rec_len
  650.                 mov di,dx                       ; presumed end of good data
  651.                 xor si,si                       ; nothing to write
  652.                 mov ax,del_mark                 ; no-deletes-yet and mark
  653.                 sub bx,cx                       ; back up
  654. packon:         add bx,cx                       ; move up a record
  655.                 cmp bx,dx                       ; done?
  656.                 jae packend                     ; if so, jump
  657.  
  658. packtest:       cmp byte ptr [bx],al            ; got a deleted one?
  659.                 je packdel                      ; jump for that too
  660.                 cmp ah,al                       ; is this first good record?
  661.                 jnz packon                      ; if not, continue
  662.                 xor ah,ah                       ; flag as got good one
  663.                 mov si,bx                       ; and mark start of good block
  664.                 jmp short packon
  665.  
  666. packdel:        cmp ah,al                       ; is this first deleted rec?
  667.                 jz packon                       ; no, continue
  668.                 mov ah,al                       ; set flag to show deletes
  669.                 cmp di,dx                       ; does di point to deleteds?
  670.                 jae packmark                    ; if not, jump
  671.                 call packit                     ; else pack
  672.                 jmp short packon                ; and carry on
  673.  
  674. packmark:       mov di,bx                       ; mark end of good block
  675.                 jmp short packon                ; and on
  676.  
  677. packend:        cmp ah,al                       ; do we have good records?
  678.                 jz packed                       ; if not, done
  679.  
  680. ;       Warning - because the following code is both called and fallen into
  681. ;       at the end, the procedure must be "near" to avoid stack crash.
  682.  
  683. packit:         cmp si,di                       ; anything to pack?
  684.                 jbe packed
  685.                 push cx
  686.                 mov cx,bx
  687.                 sub cx,si
  688.                 rep movsb
  689.                 pop cx
  690. packed:         ret
  691. packdata        endp
  692.  
  693. ;---------------------------------------------------------------------------
  694.  
  695. ;       writebuff - write the portion of rw_buff from its start to di to the
  696. ;       open file of which the handle is in new_handle.  If read_len=0, add
  697. ;       eof_mark at the end of the data and write it too.
  698. ;       Destroys bx,cx,dx; returns with ax holding # bytes written.
  699.  
  700. writebuff       proc near
  701.                 mov bx,new_handle
  702.  
  703.                 BTEST <jz writehere>
  704. if              bcond LT 1
  705.                 mov dx,write_ptr
  706.         mov cx,write_ptr+2        ; else adjust pointer
  707.         mov ax,4200h             
  708.         int 21h
  709. endif
  710.  
  711. writehere:      mov cx,di
  712.                 mov dx,offset rw_buff
  713.                 sub cx,dx
  714.                 cmp read_len,0                  ; at end of file?
  715.                 jnz writeit                     ; if not, just write
  716.                 inc cx
  717.                 mov byte ptr [di],eof_mark      ; else add the mark
  718. writeit:        jcxz writefin
  719.                 mov ax,4000h
  720.                 int 21h
  721.         jc writefin            ; error?
  722.         cmp ax,cx            ; partial write is error too
  723.  
  724. if              bcond LT 1                      ; (0)
  725.                 jb writefin
  726.                 BTEST <jz writefin>
  727. if              for386                          ; (1)
  728.         movzx eax,cx
  729.                 add dword ptr write_ptr,eax
  730. else
  731.         add write_ptr,cx
  732.         adc write_ptr+2,0
  733. endif                                           ; for386 (1)
  734. endif                                           ; bcond LT 1 (0)
  735.  
  736. writefin:       ret
  737. writebuff       endp
  738.                                                                           
  739. ;---------------------------------------------------------------------------
  740.  
  741. ;       fix_header - write system date, and record count from dbf.year, etc.,
  742. ;       to header of file whose handle is in new_handle.  Uses definitions
  743. ;       year_offset, date_n_count and write_err.
  744. ;       Destroys bx,cx,dx; returns with ax holding # bytes.
  745.                 
  746. fix_header      proc near
  747.                 mov ah,2ah                      ; get date
  748.                 int 21h
  749.                 sub cx,1900                     ; adjust year
  750.                 mov dbf.year,cl                 ; and save
  751.                 xchg dh,dl                      ; put day in dh, month in dl
  752.                 mov word ptr dbf.month,dx       ; and save back-words
  753.                 mov bx,new_handle
  754.                 xor cx,cx
  755.                 mov dx,year_offset              ; point past the first byte
  756.                 mov ax,4200h                    ; adjust file pointer
  757.                 int 21h
  758.                 mov dx,offset dbf.year          ; write from dbf storage
  759.                 mov cx,date_n_count             ; 3 bytes date, 4 # of records
  760.                 mov ah,40h                      ; write them to file
  761.                 int 21h
  762.                 mov al,write_err
  763.                 ret
  764. fix_header      endp
  765.  
  766. if bcond
  767. ;---------------------------------------------------------------------------
  768.                                  
  769. ;       rename - rename old file as .BAK and give temporary file name of
  770. ;       old file.
  771.  
  772. rename          proc near
  773.                 mov di,offset new_fname         ; replace '$$$' with 'BAK'
  774.                 mov al,dot
  775.                 mov cx,fnamelen
  776.                 repne scasb
  777.                 push di
  778.                 mov si,offset old_extension
  779.                 mov cx,2
  780.                 rep movsw
  781.                 mov dx,offset new_fname         ; delete existing .BAK file
  782.                 mov ah,41h
  783.                 int 21h
  784.                 mov dx,offset old_fname         ; rename old file as .BAK
  785.                 mov di,offset new_fname
  786.                 mov ah,56h
  787.                 int 21h
  788.                 pop di                          ; get back pointer
  789.                 mov si,offset new_extension
  790.                 mov cx,2
  791.                 rep movsw                       ; and bring back the $$$
  792.                 mov dx,offset new_fname
  793.                 mov di,offset old_fname
  794.                 mov ah,56h                      ; rename new file to old name
  795.                 int 21h
  796.                 mov al,ok_flag
  797.                 ret
  798. rename          endp
  799. endif
  800.  
  801. if tcond LT 1
  802. ;---------------------------------------------------------------------------
  803.                                  
  804. ;       convertit - convert number in dx:ax, or in eax if for386 is nonzero,
  805. ;       into right-justified ASCII string ending at ds:[bx].
  806. ;       Destroys ax,cx,dx,si or eax,ecx,edx, and returns with [bx] pointing
  807. ;       to first digit.
  808.  
  809. convertit       proc near
  810.  
  811. if for386
  812.                 mov ecx,10
  813. nextdiv:        xor edx,edx
  814.                 div ecx
  815. else
  816.                 mov cx,10
  817. nextdiv:        mov si,ax                       ; save low word of value
  818.                 mov ax,dx                       ; divide high word only
  819.                 xor dx,dx
  820.                 div cx                          ; dx now holds high remainder
  821.                 xchg si,ax                      ; save hi quotient/get low word
  822.                 div cx                          ; divide hi rem:low word by 10
  823. endif
  824.                 dec bx                          ; back up
  825.                 or dl,30h                       ; convert low rem to ASCII
  826.                 mov [bx],dl                     ; and place it in string
  827. if for386
  828.                 or eax,eax
  829. else
  830.                 mov dx,si                       ; get hi quotient back
  831.                 or si,ax                        ; test for done
  832. endif
  833.                 jnz nextdiv
  834.                 ret
  835. convertit       endp
  836. endif
  837.  
  838. if DOSexe
  839. old_fname       equ $                           ; path & name of source file
  840. new_fname       equ old_fname+fnamelen          ; & target file
  841. rw_buff         equ new_fname+fnamelen
  842. endif
  843.  
  844. CODESEG         ends
  845.                 end start
  846.  
  847.